﻿#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<list>
#include<deque>
using namespace std;

//class Person
//{
//public:
//	void identity()
//	{
//		cout << "void sodentity()" <<_name << endl;   
//		cout << _age << endl;      //在父类中可以使用   一旦后续调用这个函数   就间接使用
//	}
//
//protected:
//	string _name = "张三";    //姓名
//	string _address;          //地址
//	string _tel;              //电话
//private:
//	int _age=18; //年龄    虽然这个继承后在类内外都不可见  但是在这个父类里面是可以使用的   可以在公有函数中进行使用
//	//也就是上面的identity()     公共函数中使用     在子类中一调用这个函数，就会间接访问使用到了这个私有成员变量
//};
//
//class Student :public Person    //这是表示  Student类对Person类进行继承
//{
//public:
//	void study()
//	{
//		//.....
//		//cout << _age << endl;     //会报错   私有成员无法访问（类内和外都不能使用）
//		cout << _name<< endl;       //这个正常访问
//	}
//	
//protected:
//	int _stuid;               //表示学生学号    
//};
//
//class Teacher :public Person
//{
//public:
//	//授课
//	void teaching()
//	{
//		//.....
//	}
//
//protected:
//	string _title;            //职称
//};

/* 这里面的Person是父类，也称作为基类。Student是子类，也称作为派生类 */

//int main()
//{
//	Student s;
//	Teacher t;
//
//	s.identity();      //身份认证函数
//	t.identity();      //虽然没有定义这个对应的函数   但是继承的类中有   所以是可以进行使用的   体现复用
//
//	return 0;
//}

//定义宏  可以用来替换模板（可以不写死直接替换）   下面的class stack:public std::list<T> ----->class stack:public CONTAINER<T>
#define CONTAINER std::list
//#define CONTAINER std::deque
//#define CONTAINER std::vector

//继承方式模拟实现栈
namespace lcx
{
/*
	//stack和vector的关系，既符合is-a,也符合has-a
	template<class T>
	class stack :public std::vector<T>  //这个表示继承的是库中的vector  用int的时候就会实例化一个整型vector  不会把所有函数都实例化
	{
	public:
		void push(const T& x)
		{ 
			vector<T>::push_back(x);     
		  //这里就需要指定一下类域   
		  //会发现  只有push_back是找不到对应的  复用vector的push_back的时候无法调用  因为按需实例化
		} //调用哪个函数才会实例化哪个函数（用到谁就实例化谁）

		void pop()
		{
			vector<T>::pop_back();
		}

		const T& top()
		{
			return vector<T>::back();
		}

		bool empty() 
		{
			return vector<T>::empty();
		}
	};
	//父类是类模板时，需要指定一下类域    否则就会编译报错：找不到标志符
	//因为stack<int>实例化时，也实例化vector<int> 了    但是模板是按需实例化  push_back 等成员函数没有实例化   所以找不到
*/
}


/*
	//模拟实现list
	template<class T>
	class stack :public CONTAINER<T>    //这里的栈就是实例化list实例化出来的
	{
	public:
		void push(const T& x)
		{
			CONTAINER<T>::push_back(x);    //这里指定list<T>  继承父类是模板就需要指定一下   方便实例化模板
		}

		void pop()
		{
			CONTAINER<T>::pop_back();
		}
		
		const T& top()
		{
			return CONTAINER<T>::back();
		}

		bool empty()
		{
			return CONTAINER<T>::empty();
		}
	};
}

//依赖模板参数的都不进行实例化   不依赖的才会检查   当不调用相关对应函数的时候是不会进行实例化的，不实例化也不会作相关的检查
//调用的时候才会真正检查有无错误

	int main()
	{
		lcx::stack<int> st;   //这一句只会实例化栈的构造函数
		st.push(1);    //这就会实例化push_back   并实例化成int
		st.push(2);
		st.push(3);    //只有用到这个函数才会实例化这个函数
		st.push(4);

		while (!st.empty())
		{
			cout << st.top() << " ";
			st.pop();
		}
		return 0;
*/



/*
//父类子类对象赋值兼容转换
class Person
{
//protected:
	virtual void func()  
	{};    //虚函数（跟多态有关系） 

public:
	string _name;    //姓名
	string _sex;     //性别
	int _age;        //年龄
};

class Student:public Person
{
public:
	int _No;         //学号
};

int main()
{
	Student sobj;
	//1.子类对象可以赋值给父类对象/指针/引用
	Person pobj = sobj;   
	Person* pp = &sobj;
	Person& rp = sobj;    //子类的对象可以给父类   没有发生类型转换    没有产生临时变量（临时变量有常性  会导致权限放大）
	rp._name = "张三";    //这里如果影响并修改  需要上面的父类是public

	//类似： int i=1;   const double& rd = i;    就会产生临时变量（具有常性）

	//2.父类对象不能赋值给子类对象   会导致编译报错
	//sobj =(Student)pobj;     //这就会导致编译错误   即使类型强转也是通不过

	//但是指针可以   指针单独使用不行但是指针可以强转
	Student* ps = (Student*)pp;
	
	//也就是说父类的指针指向子类转回子类是没问题的
	Student* ps1 = dynamic_cast<Student*>(pp);    //转换成功会返回正常指针   不成功则会返回空    但是要求是多态类型(虚函数类型)
	cout << ps1 << endl;     //虚函数类型就是virtual 关键字   虚函数 virtual void func() {}      这样就转换成功了（加上虚函数）
	
	//如果指向父类  转回子类是不行的    dynamic_cast强转
	pp = &pobj;
	Student* ps2 = dynamic_cast<Student*>(pp);
	cout << ps2 << endl;    //这种转换就是失败的

	return 0;
}

*/


/*
//继承中的作用域
class Person
{
protected:
	string _name = "小李";  //姓名
	int _num = 111;     //身份证号
};

class Student :public Person     //一旦继承父类  相当于有两个 _num
{
public:
	void Print()
	{
		cout << _num << endl;      //这个会输出999
		cout << Person::_num << endl;    //这个输出111
	}

protected:
	int _num = 999;     //学号
};

int main()
{
	Student s;
	s.Print();    //输出999   会优先考虑就近的查找   子类的同名变量隐藏了父类的    如果说指明对应的父类还是可以访问的
	return 0;
}

*/

/*
//题目1
class A
{
public:
	void fun()
	{
		cout << "func()" << endl;
	}
};

class B : public A         //B继承A   
{
public:
	void func(int i)
	{
		cout << "func(int i)" << i << endl;
	}
};

	A和B类中两个func 构成什么关系？
	答：构成隐藏    不是重载（因为重载是要求在同一作用域）     他们在不同的作用域

*/

/*
//题目2
class A
{
public:
	void fun()
	{
		cout << "func()" << endl;
	}
};

class B : public A         //B继承A   
{
public:
	void func()
	{
		cout << "func()" << endl;
	}
};

	A和B中的func 构成什么关系？
    A.重载     B.隐藏     C.没有关系    D.编译报错
	答：隐藏关系
*/


/*
//特殊情况
class A
{
public:
	void fun()
	{
		cout << "func()" << endl;
	}
};

class B :public A
{
public:
	void fun(int i)
	{
		cout << "func(int i)" << i << endl;
	}
};

int main()
{
	B b;
	b.A::fun();      //会出现这里调不到的问题
	return 0;
}

	因为：他会先在派生类里面进行搜索，到fun的时候会认为参数不匹配，不会再去父类进行搜索（派生类隐藏了父类）
		  只要函数名相同就会构成隐藏，想调用就只能指定作用域
*/

/*
//题目3
class A
{
public:
	void fun()
	{
		cout << "func()" << endl;
	}
};

class B :public A
{
public:
	void fun(int i)
	{
		cout << "func(int i)" << i << endl;
	}
};

int main()
{
	B b;
	b.fun(10);
	b.fun();    //------>需要修改为b.A::fun();

	return 0;
}

	这段代码会发生什么？
	答：会编译报错   
		因为他会先在派生类里面进行搜索，到fun的时候会认为参数不匹配，不会再去父类进行搜索（派生类隐藏了父类）
		只要函数名相同就会构成隐藏，想调用就只能指定作用域

*/


/*
	1.子类的构造函数必须调用父类的构造函数初始化父类的那一部分成员。如果父类没有默认的构造函数，
	  则必须在子类构造函数的初始化列表阶段显示调用
*/
#if 0
class Person
{
public:
	//Person(const char* name = "peter")
	Person(const char* name)       //这种是不给默认构造的
		:_name(name)
	{
		cout << "Person()" << endl;
	}

	Person(const Person& p)
		:_name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}

	Person& operator=(const Person& p)
	{
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)
			_name = p._name;

		return *this;
	}

	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string  _name;     //姓名
};


class Student :public Person       //Student类继承Person类
{
public:
	//这个子类不写构造函数，默认生成的构造函数的行为是
		//1.内置类型（不确定）
		//2.自定义类型（调用默认构造   没有就报错）
		//3.继承父类成员看做一个整体对象，要求调用父类的默认构造

//严格说  Student拷贝构造默认生成的就够用    因为只有内置类型和自定义类型的两个
//当 类中有需要进行深拷贝的资源的时候，才需要自己实现拷贝构造，析构     一般子类构造要自己写，拷贝构造/析构/赋值不需要

	Student(const char* name, int num, const char* address)
		:
		//_name(name), 
//！！注意：这里是无法在子类中直接定义初始化父类的那一部分成员的，必须调用父类默认构造，
//！！没有就需要在子类构造函数的初始化列表阶段显示调用
		Person(name),         //这就是显示调用   类似于匿名对象    父类多参数就传多个    父类是一个整体对象
	//上面是父类成员     下面是子类成员
		_num(num),
		_address(address)
	{}

//初始化列表跟写的顺序无关  跟声明的顺序有关  会先调用Person
	//自己显示实现拷贝构造
	Student(const Student& s)
		:
		_num(s._num),
		_address(s._address),
		Person(s)    //调用父类的拷贝构造  需要传父类对象  但是没有父类对象  就传子类对象  传过去之后会自然切割
	{
		//这里面添加写深拷贝的内容
	}

	//自己显示实现赋值重载
	Student& operator=(const Student& s)
	{
		if (this != &s)
		{
			//operator=(s);      //显示调用父类的赋值   把子类传过去   会自动切割
	//但是注意：这里会导致无限递归而栈溢出    这是因为子类的同名函数operator=和父类同名函数构成隐藏   也就需要指定调用
			Person::operator=(s);
			_num = s._num;
			_address = s._address;
		}
		return *this;
	}

	//所有的析构都会特殊处理成destructor()   两个都是   故构成隐藏
	~Student()
	{
	//子类的析构和父类的析构函数也构成隐藏关系
		//Person::~Person();   
	//析构可以显示调用  但是这里的子类无法使用父类的析构   因为子类的析构和父类的析构构成隐藏关系
	//需要进行指定才能进行调用
	
	//但是规定：不需要显示调用   子类析构函数之后，会自动调用父类析构
	//这样是为了保证析构的顺序   先子后父，显示调用就取决于实现的人了，不能保证先子后父
	}

	/*
		拷贝构造   赋值重载   析构        都是类似
		拷贝构造：对于内置类型进行值拷贝      对于自定义类型调用他自身的拷贝构造     对于父类的对象调用父类中的拷贝构造
		赋值重载：严格说这里的赋值重载默认生成的就够用     如果有需要深拷贝的资源，才需要自己实现
		析构：严格说这里的析构也够用   不需要怎么处理   若有需要显示释放的资源，才需要自己实现

		也就是一般情况    父类的对象部分 拷贝构造/赋值重载/析构需要显示调用父类的  析构不显示调用
		父类对象调用父类的
	*/

public:
	//对于内置类型：默认生成的构造函数不确定，对于自定义类型会去调用构造函数
	int _num = 111;   //学号
	string _address = "江苏省";     //这是相当于添加缺省值   走成员列表的时候会用
};

int main()
{
	//Student s;    //这里调用默认构造（内置类型不初始化，自定义类型    父类整体调用父类的默认构造）
	//一旦父类不提供默认构造   上面的就无法自动生成    就需要显示构造在子类中
	
	Student s1("张三", 222, "江苏省");     //构造函数
	Student s2(s1);     //拷贝构造

	Student s3("李四", 2, "上海市");
	s1 = s3;    
	//调试发现  三个对象会调用了6次析构

	return 0;
}
#endif


//实现一个不能被继承的类
//class Base /* final */    //这个final就是最终类   最终类不能被继承
//{
//public:
//	void func1()
//	{
//		cout << " Base::func1 " << endl;
//	}
//protected:
//	int a = 1;
//private:
//	//C++ 98的方法   父类函数私有化就不能被继承
//	Base()
//	{}
//};
//
//class Derive :public Base
//{
//	void func2()
//	{
//		cout << " Derive::func2 " << endl;
//	}
//};
//
//int main()
//{
//	return 0;
//}


////前置声明
//class Student;   //加上一个Student的声明
//
////友元不能被继承
//class Person
//{
//public:
//	friend void Display(const Person& p, const Student& s);    //友元关系不能被继承   解决方法   再在下面加上一个友元
//protected:
//	string _name;    //姓名
//};
//
//class Student :public Person
//{
//	//加友元解决
//	friend void Display(const Person& p, const Student& s);
//protected:
//	int _stuNum;    //学号
//};
//
//void Display(const Person& p, const Student& s)
//{
//	cout << p._name << endl;
//	cout << s._stuNum << endl;     //友元不能被继承  也就是说   友元是Person的  Student虽然继承了Person但是友元不会被继承下来
//}
//
////一般只会向上查找   当报错但是没有找到错误的时候  可能就是向上查找的问题   
////上面的就是   因为Student要依赖父类   父类的Student类又找不到   所以就会出现问题     可以通过加上前置声明解决
//int main()
//{
//	Person p;
//	Student s;
//
//	Display(p, s); 
//	return 0;
//}


//继承和静态成员
//class Person
//{
//public:
//	string _name;
//	static int _count;
//};
//
//int Person::_count = 0;
//
//class Student :public Person
//{
//protected:
//	int _stuNum;
//};
//
//int main()
//{
//	Person p;
//	Student s;
//	
//	//这里的运行结果可以看到非静态成员  _name 的地址不一样
//	//说明子类继承下来了，父子类对象各有一份
//	cout << &p._name << endl;
//	cout << &s._name << endl;
//
//	//这里运行结果可以看到静态成员 _count的地址是一样的
//	//说明子类和父类共用同一份静态成员
//	cout << &p._count << endl;
//	cout << &s._count << endl;
//
//	//共有的情况下，父子类指定类域都可以访问静态成员
//	cout << Person::_count << endl;
//	cout << Student::_count << endl;    //这是用类域进行访问的（一般使用类域访问）
//
//	//也可以使用对象进行访问
//	cout << p._count << endl;
//	cout << s._count << endl;   //和上面的类域访问结果一致（一般不用）
//	
//	return 0;
//}


////菱形继承的问题   数据冗余和二义性（二义性是自己不知道自己访问的是谁）
//class Person     //单独的父类
//{
//public:
//	string _name;    //姓名
//	int _tel; 
//	int _age;
//	string _gender;    //性别 
//	string _address;   //地址
//	//...
//};
//
//class Student :virtual public Person
//{
//protected:
//	int _num;    //学号
//};
//
//class Teacher :virtual public Person     //Person有数据冗余   就在这的继承前面加上virtual   改为虚继承
//{
//protected:
//	int _id;     //教职工编号
//};
//
//class Assistant :public Student, public Teacher    //解决的是最下面这个类的问题
//{
//protected:
//	string _majorCourse;    //主修课程
//};
//
//int main()
//{
//	Assistant a;       //因为这里面有两个_name  
//	a._name = "peter";     //这里会爆出编译错误   对_name的访问不明确    加上virtual就没有问题了   
//
//	//下面需显示指定访问哪个父类的成员可以解决二义性问题，但是数据冗余问题无法解决
//	a.Student::_name = "xxx";    
//	a.Teacher::_name = "yyy";
//	return 0;
//}


class Base1
{
public:
	int _b1;
};

class Base2
{
public:
	int _b2;
};

class Derive :public Base1, public Base2     //继承了  1和2
{
public:
	int _d;
};

int main()
{
	Derive d;
	Base1* p1 = &d;      //先声明的也在前面   继承的父类也在前    
	Base2* p2 = &d;
	Derive* p3 = &d;     //p3指向开始

	return 0;
}
//p1和p3相同    p2不同    先继承的在前
